/*----------------------------------------------------------------------------/
/  8-pin SD audio player R0.05c                    (C)ChaN, 2011              /
/-----------------------------------------------------------------------------/
/ This project, program codes and circuit diagrams, is opened under license
/ policy of following trems.
/
/  Copyright (C) 2010, ChaN, all right reserved.
/
/ * This project is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/   personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/----------------------------------------------------------------------------*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include <string.h>
#include "pff.h"
#include "typedef.h"
#include "wavePlayer.h"
#include "DS18x20_simpleFunc.h"
#include "TempSensor.h"
#include "Tools.h"
#include "USART_simpleFunc.h"


#define FCC(c1,c2,c3,c4)	(((DWORD)c4<<24)+((DWORD)c3<<16)+((WORD)c2<<8)+(BYTE)c1)	/* FourCC */

void delay_us (WORD);	/* Defined in asmfunc.S */
extern void portDebug(BOOL bStatus);
extern void portDebugBlinker(u8 u8Counter);


/*---------------------------------------------------------*/
/* Work Area                                               */
/*---------------------------------------------------------*/

volatile BYTE FifoRi, FifoWi, FifoCt;	/* FIFO controls */

BYTE Buff[256];		/* Wave output FIFO */

FATFS Fs;			/* File system object */
DIR Dir;			/* Directory object */
FILINFO Fno;		/* File information */

WORD rb;			/* Return value. Put this here to avoid avr-gcc's bug */



/*---------------------------------------------------------*/

static
DWORD load_header (void)	/* 0:Invalid format, 1:I/O error, >=1024:Number of samples */
{
	DWORD sz, f;
	BYTE b, al = 0;


	if (pf_read(Buff, 12, &rb)) return 1;	/* Load file header (12 bytes) */

	if (rb != 12 || LD_DWORD(Buff+8) != FCC('W','A','V','E'))
	{
		return 0;
	}

	for (;;) {
		//wdt_reset();
		pf_read(Buff, 8, &rb);			/* Get Chunk ID and size */
		if (rb != 8)
		{
			return 0;
		}
		sz = LD_DWORD(&Buff[4]);		/* Chunk size */

		switch (LD_DWORD(&Buff[0])) {	/* FCC */
		case FCC('f','m','t',' ') :					/* 'fmt ' chunk */
			if (sz & 1) sz++;						/* Align chunk size */
			if (sz > 100 || sz < 16) 		/* Check chunk size */
			{
				return 0;
			}
			pf_read(Buff, sz, &rb);					/* Get content */
			if (rb != sz)
			{
				return 0;
			}
			if (Buff[0] != 1) 			/* Check coding type (LPCM) */
			{
				return 0;
			}
			b = Buff[2];
			if (b != 1) 			/* Check channels (1) */
			{
				return 0;
			}
			al = b;
			b = Buff[14];
			if (b != 8)				/* Check resolution (8 bit) */
			{
				return 0;
			}
			if (b & 16) al <<= 1;
			f = LD_DWORD(&Buff[4]);					/* Check sampling freqency (8k-48k) */
			if (f != 8000) return 4;
			OCR1A = (BYTE)(F_CPU / 8 / f) - 1;		/* Sampling freq */
			break;

		case FCC('d','a','t','a') :		/* 'data' chunk */
			if (!al) 						/* Check if format valid */
			{
				return 0;
			}
			if (sz < 1024 || (sz & (al - 1))) 	/* Check size */
			{
				return 0;
			}
			if (Fs.fptr & (al - 1)) 			/* Check offset */
			{
				return 0;
			}
			return sz;									/* Start to play */

		case FCC('D','I','S','P') :		/* 'DISP' chunk */
		case FCC('L','I','S','T') :		/* 'LIST' chunk */
		case FCC('f','a','c','t') :		/* 'fact' chunk */
			if (sz & 1) sz++;				/* Align chunk size */
			pf_lseek(Fs.fptr + sz);			/* Skip this chunk */
			break;

		default :						/* Unknown chunk */
		{
			return 0;
		}

		}
	}
	return 0;
}



static
void ramp (
	int dir		/* 0:Ramp-down, 1:Ramp-up */
)
{
	BYTE v, d, n;


	if (dir) {
		v = 0; d = 1;
	} else {
		v = 128; d = (BYTE)-1;
	}

	n = 128;
	do {
		v += d;
		OCR2 = v;
		delay_us(100);
	} while (--n);
}



FRESULT play (
	const char *dir,	/* Directory */
	const char *fn		/* File */
)
{
	DWORD sz;
	FRESULT res;
	BYTE sw;
	WORD btr;


	strcpy((char*)Buff, dir);	/* sprintf(Buff, "%s/%s", dir, fn); */
	strcat((char*)Buff, "/");
	strcat((char*)Buff, fn);

	//wdt_reset();
	res = pf_open((char*)Buff);		/* Open sound file */
	if (res == FR_OK) {
		sz = load_header();			/* Check file format and ready to play */
		if (sz < 1024) return 255;	/* Cannot play this file */
		if (!TCCR2) {				/* Enable audio out if not enabled */
			TCCR2 = 0b01101001; //fast PWM, clear Pin on compare match, enable PWM no prescaling
			TCCR1A = 0b00000000; //normal port operation, CTC
			TCCR1B = 0b00001010; //CTC, clk/8 -> 16/8=2MHz
			TIMSK = _BV(OCIE1A);
			ramp(1);
		}

		FifoCt = 0; FifoRi = 0; FifoWi = 0;		/* Reset FIFO */
		pf_read(0, 512 - (Fs.fptr % 512), &rb);	/* Snip sector unaligned part */
		sz -= rb;

		sw = 1;		/* Button status flag */
		do {
			//wdt_reset();
			/* Forward audio data */
			btr = (sz > 1024) ? 1024 : (WORD)sz;/* A chunk of audio data */
			res = pf_read(0, btr, &rb);			/* Forward the data into audio FIFO */
			if (res != FR_OK || btr != rb) break;
			sz -= rb;
			/* Check button down and break on button down */
			sw <<= 1;
			//if (bit_is_clear(PINB, 0) && ++sw == 1) break;
		} while (rb == 1024);	/* Repeat until all data forwarded */
	}

	while (FifoCt) ;			/* Wait for audio FIFO empty */
	OCR2 = 128;	/* Return output to center */

	return res;
}


//static
//void delay500 (void)
//{
//	wdt_reset();
//	TCCR1B = 0; TCCR1A = 0;	/* Stop TC1 */
//
//	if (TCCR2) {
//		ramp(0);
//		TCCR2 = 0; 	/* Stop TC2 */
//	}
//
//	WDTCR = _BV(WDE) | _BV(WDIE) | 0b101;	/* Enable WDT interrupt in timeout of 0.5s */
//	set_sleep_mode(SLEEP_MODE_PWR_DOWN);	/* Enter power down mode */
//	sleep_mode();
//
//	wdt_reset();
//	WDTCR = _BV(WDE) | 0b110;				/* Enable WDT reset in timeout of 1s */
//}



/*-----------------------------------------------------------------------*/
/* Main                                                                  */

int main (void)
{
	FRESULT res;
	char *dir;
	u8 u8Temperature;
	b8 b8Sign;
	u8 i;

	MCUSR = 0;
	//WDTCR = _BV(WDE) | 0b110;	/* Enable WDT reset in timeout of 1s */

	//PORTB = 0;		/* Initialize port: - - H L H L L P */
	//DDRB  = _BV(PB3); //PWM output
	
	PORTC = 0b00001010;
	DDRC =  0b00001101;

	U8_SET_BIT(DDRB,PB3); //OUTPUT

	sei();

	initUSART();

	portDebugBlinker(2);

	for (;;) {
		if (pf_mount(&Fs) == FR_OK)
		{	/* Initialize FS */
			transmitUSART(0xAA);
			//wdt_reset();
			//Buff[0] = 0;
			//if (!pf_open("osccal")) pf_read(Buff, 1, &rb);	/* Adjust oscillator frequency */
			//OSCCAL = org_osc + Buff[0];

			res = pf_opendir(&Dir, dir = "wav");	/* Open sound file directory */
			transmitUSART(res);
			if (res == FR_NO_PATH) {
				res = pf_opendir(&Dir, dir = "");	/* Open root directory if no sound dir */
			}

			while (res == FR_OK) {
				res = pf_readdir(&Dir, 0);			/* Rewind dir */
				while (res == FR_OK) {				/* Play all wav files in the dir */
					//wdt_reset();
					res = pf_readdir(&Dir, &Fno);		/* Get a dir entry */
					if (res || !Fno.fname[0]) break;	/* Break on error or end of dir */
					if (!(Fno.fattrib & (AM_DIR|AM_HID)) && strstr(Fno.fname, ".WAV"))
					{
						if(GetTemperature(&u8Temperature, &b8Sign) == 1) vPlayTemperature(u8Temperature, b8Sign);
					}
				}
			}
		}
		else
		{
			transmitUSART(0xBB);
		}
		TCCR1A = 0;	TCCR1B = 0;/* Stop TC0 */
		_delay_ms(500);			/* Delay 500ms in low power sleep mode */
	}
}

void portDebug(BOOL bStatus)
{
	U8_SET_BIT(DDRC,PC5); //OUTPUT
	U8_BIT_ASSIGN(PORTC, PC5, bStatus);
}

void portDebugBlinker(u8 u8Counter)
{
	u8 i = 0;
	U8_SET_BIT(DDRC,PC5); //OUTPUT
	U8_BIT_ASSIGN(PORTC, PC5, 0);

	while(i < u8Counter)
	{
		U8_BIT_ASSIGN(PORTC, PC5, 1);
		_delay_ms(500);
		_delay_ms(200);
		U8_BIT_ASSIGN(PORTC, PC5, 0);
		_delay_ms(500);
		_delay_ms(200);

		i++;
	}
	_delay_ms(500);
	_delay_ms(500);
	_delay_ms(500);
	//_delay_ms(500);

}

